#pragma

#include <iostream>
#include <queue>
#include <pthread.h>


template<class T>
class BlockQueue
{
    static const int defalutnum = 20;
public:
    BlockQueue(int maxcap = defalutnum)
        :maxcap_(maxcap)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&c_cond_, nullptr);
        pthread_cond_init(&p_cond_, nullptr);
        // low_water_ = maxcap_/3;
        // high_water_ = maxcap_*2/3;
    }

    T pop()
    {
        pthread_mutex_lock(&mutex_);
        while(q_.size() == 0) //因为判断临界资条件是否满足，也是在访问临界资源，判断资源是否就绪，是通过临界资源内部判断的
        {
            //如果线程wait时，被误唤醒呢？
            pthread_cond_wait(&c_cond_, &mutex_); //这里我们还是持有锁的！1.调用的时候自动释放锁，因为唤醒而返回的时候，重新持有锁
        }
        T out = q_.front();
        q_.pop();
        // if(q_.size() < low_water_)
        // {
            //pthread_cond_broadcast(&p_cond_); //放在锁里面和外面都可以的
            pthread_cond_signal(&p_cond_); //放在锁里面和外面都可以的
        // }
        pthread_mutex_unlock(&mutex_);
        return out;
    }
    void push(const T& in)
    {
        pthread_mutex_lock(&mutex_);
        while(q_.size() == maxcap_) //已经满了，不能生产了
        {
            pthread_cond_wait(&p_cond_, &mutex_); //调用的时候自动释放锁
        }
        //队列没满或者没唤醒
        q_.push(in);
        // if(q_.size() > high_water_)
        // {
            pthread_cond_signal(&c_cond_);
        // }
        pthread_mutex_unlock(&mutex_);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&c_cond_);
        pthread_cond_destroy(&p_cond_);
    }
private:
    std::queue<T> q_; //多线程访问的共享资源,q是被当成整体使用的，q只有一份。加锁。但是共享资源也是可以被看成多份的！
    //int mincap_;
    int maxcap_;     //极值
    pthread_mutex_t mutex_; //因为STL不是线程安全的，我们需要保护它
    pthread_cond_t c_cond_; 
    pthread_cond_t p_cond_; 
    // int low_water_;
    // int high_water_;
};